package smallfrench.moteur.biblio.igu;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;

import smallfrench.moteur.biblio.AClasse;
import smallfrench.moteur.biblio.AObjet;
import smallfrench.moteur.biblio.AVecteur2;
import smallfrench.moteur.biblio.AnnotationMembre;
import smallfrench.moteur.biblio.RChaine;
import smallfrench.moteur.biblio.RCouleur;
import smallfrench.moteur.biblio.REntier;
import smallfrench.moteur.biblio.RFlottant;

/**
 * Représente la courbe d'une fonction mathématique.
 * TODO: réécrire transformations
 * @author antoine1023
 */
public class Courbe extends AObjet {

	public static final AClasse CLASSE = AClasse.creer(Courbe.class);

	/** La couleur du trait */
	private Color couleur = Color.BLUE;

	private ArrayList<AVecteur2> points;

	/** L'épaisseur du trait */
	private RFlottant epaisseur = new RFlottant(2.0);

	//-------------------------------------------------------------------------

	@AnnotationMembre
	public Courbe() {
		points = new ArrayList<AVecteur2>();
	}

	//-------------------------------------------------------------------------

	@AnnotationMembre
	public void ajouterPoint(RFlottant x, RFlottant y) {
		points.add(new AVecteur2(x, y));
	}

	public AVecteur2 obtenirPoint(REntier i) {
		return points.get(i.getValeurInt());
	}

	//-------------------------------------------------------------------------

	@AnnotationMembre
	public void modifierCouleur(RCouleur couleur) {
		this.couleur = couleur.valeur;
	}

	@AnnotationMembre
	public void modifierEpaisseur(RFlottant epaisseur) {
		this.epaisseur = epaisseur;
	}

	//-------------------------------------------------------------------------

	@AnnotationMembre
	public RFlottant obtenirMinimumX() {

		if (points.size() == 0)
			return null;

		double min = points.get(0).x;

		for (int i = 1; i < points.size(); i++) {
			AVecteur2 v = points.get(i);
			if (v.x < min)
				min = v.x;
		}

		return new RFlottant(min);
	}

	@AnnotationMembre
	public RFlottant obtenirMaximumX() {

		if (points.size() == 0)
			return null;

		double max = points.get(0).x;

		for (int i = 1; i < points.size(); i++) {
			AVecteur2 v = points.get(i);
			if (v.x > max)
				max = v.x;
		}

		return new RFlottant(max);
	}

	@AnnotationMembre
	public RFlottant obtenirMinimumY() {

		if (points.size() == 0)
			return null;

		double min = points.get(0).y;

		for (int i = 1; i < points.size(); i++) {
			AVecteur2 v = points.get(i);
			if (v.y < min)
				min = v.y;
		}

		return new RFlottant(min);
	}

	@AnnotationMembre
	public RFlottant obtenirMaximumY() {

		if (points.size() == 0)
			return null;

		double max = points.get(0).y;

		for (int i = 1; i < points.size(); i++) {
			AVecteur2 v = points.get(i);
			if (v.y > max)
				max = v.y;
		}

		return new RFlottant(max);
	}

	public AVecteur2[] transformer(Transformation t, double tx, double ty) {

		AVecteur2[] pt = new AVecteur2[points.size()];
		for (int i = 0; i < pt.length; i++) {
			pt[i] = t.transformer(points.get(i).ajouter(tx, ty));
		}

		return pt;
	}

	/**
	 * Affiche la courbe.
	 * @param g
	 * @param tailleX La largeur de la fenêtre en pixels
	 * @param tailleY La hauteur de la fenêtre en pixels
	 * @param posFenetreX La position de la fenêtre
	 * @param posFenetreY La position de la fenêtre
	 * @param t La transformation affine
	 */
	public void dessiner(Graphics2D g,
			int tailleX, int tailleY,
			double posFenetreX, double posFenetreY,
			Transformation t) {

		g.setColor(couleur);

		g.setStroke(new BasicStroke(epaisseur.getValeurFloat()));

		if (points.size() < 2) return;

		AVecteur2[] pt = transformer(t, -posFenetreX, -posFenetreY);
		AVecteur2 a = pt[0];

		for (int i = 1; i < pt.length; i++) {
			AVecteur2 b = pt[i];
			g.draw(new Line2D.Double(a.x, tailleY-a.y, b.x, tailleY-b.y));
			a = b;
		}
	}

	//-------------------------------------------------------------------------

	@Override
	@AnnotationMembre
	public RChaine enChaine() {
		return new RChaine("Courbe");
	}

}
